﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Globalization;
using System.Configuration;

namespace YasharEl.Infrastructure.ObjectFactory.Unity
{
    public class UnityDependencyResolver : IDependencyResolver
    {
        #region ReadOnly Fields

        protected IUnityContainer unityContainer;

        #endregion

        #region Constructors

        public UnityDependencyResolver(IUnityContainer unityContainer)
        {
            Contract.Requires<ArgumentNullException>(unityContainer != null, "unityContainer could not be null.");
            this.unityContainer = unityContainer;
        }

        #endregion

        #region IDependencyResolver Impelemntations

        public TService Resolve<TService>()
        {
            return unityContainer.Resolve<TService>();
        }

        public TService Resolve<TService>(string key)
        {
            return unityContainer.Resolve<TService>(key);
        }

        public object Resolve(Type type)
        {
            return unityContainer.Resolve(type);
        }

        public object Resolve(Type type, string key)
        {
            return unityContainer.Resolve(type, key);
        }

        public IEnumerable<TService> ResolveAllInstances<TService>()
        {
            return unityContainer.ResolveAll<TService>();
        }

        public IEnumerable<object> ResolveAllInstances(Type type)
        {
            return unityContainer.ResolveAll(type);
        }

        #endregion

        #region Internal Classes

        internal static IUnityContainer Resolve(string unitySectionName, string containerName)
        {
            if (string.IsNullOrEmpty(unitySectionName))
            {
                unitySectionName = UnityConfigurationSection.SectionName;
            }
            UnityConfigurationSection config = null;
            config = (UnityConfigurationSection)ConfigurationManager.GetSection(unitySectionName);

            if (config == null)
                throw new DependencyContainerConfigurationException("No Unity configuration was found.");

            if (config.Containers == null || config.Containers.Count == 0)
                throw new DependencyContainerConfigurationException("No Unity containers have been configured.");

            ContainerElement containerConfig;

            if (string.IsNullOrEmpty(containerName))
            {
                containerConfig = config.Containers.Default;

                if (containerConfig == null)
                {
                    throw new DependencyContainerConfigurationException("The default Unity container was not found in configuration.");
                }
            }
            else
            {
                containerConfig = config.Containers[containerName];

                if (containerConfig == null)
                {
                    String message = String.Format(
                        CultureInfo.InvariantCulture, "No Unity container with the name '{0}' was not found in configuration.", containerName);

                    throw new DependencyContainerConfigurationException(message);
                }
            }

            IUnityContainer container = new UnityContainer();

            config.Configure(container, containerName);
            return container;
        }

        #endregion
    }
}
